package me.awei.toolbar.snackbar;


import me.awei.toolbar.ResourceTable;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.utils.Sequenceable;

import java.util.LinkedList;
import java.util.Queue;

class SnackContainer extends StackLayout {

    private static final int ANIMATION_DURATION = 300;

    private static final String SAVED_MSGS = "SAVED_MSGS";

    private Queue<SnackHolder> mSnacks = new LinkedList<SnackHolder>();

    private AnimatorGroup mOutAnimationSet;
    private AnimatorGroup mInAnimationSet;
    private AnimatorProperty mSlideInAnimation;
    private AnimatorProperty mSlideOutAnimation;

    private float mPreviousY;

    //使用eventHandler
    private EventHandler handler;

    public SnackContainer(Context context) {
        super(context);
        init();
    }

    public SnackContainer(Context context, AttrSet attrs) {
        super(context, attrs);
        init();
    }

    SnackContainer(ComponentContainer container) {
        super(container.getContext());

        if (container instanceof DirectionalLayout) {
            DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, 200);
            layoutConfig.alignment = TextAlignment.BOTTOM;
            container.addComponent(this, layoutConfig);
        } else {
            ComponentContainer.LayoutConfig layoutConfig = container.getLayoutConfig();
            container.addComponent(this, new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, 200));
        }
        setVisibility(Component.HIDE);
        setId(ResourceTable.Id_snackContainer);
        init();
    }

    private void init() {
        mInAnimationSet = new AnimatorGroup();

        mSlideInAnimation = new AnimatorProperty();
        mSlideInAnimation.alpha(0.9f).moveFromX(0.0f).moveToX(0.0f).moveFromY(1.0f).moveToY(0.0f);
        mOutAnimationSet = new AnimatorGroup();
        mSlideOutAnimation = new AnimatorProperty();
        mSlideOutAnimation.alpha(0.1f).moveFromX(0.0f).moveToX(0.0f).moveFromY(0.0f).moveToY(1.0f);
        mSlideOutAnimation.setDuration(ANIMATION_DURATION);
        mSlideOutAnimation.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                mOutAnimationSet.end();
            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                removeAllComponents();

                if (!mSnacks.isEmpty()) {
                    sendOnHide(mSnacks.poll());
                }

                if (!isEmpty()) {
                    showSnack(mSnacks.peek());
                } else {
                    setVisibility(Component.HIDE);
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
    }

    //    @Override
    protected void onDetachedFromWindow(Component component) {
        BindStateChangedListener bindStateChangedListener = new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {

            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {

            }
        };
        bindStateChangedListener.onComponentUnboundFromWindow(component);
        mSlideInAnimation.cancel();
        mSlideOutAnimation.cancel();
        handler = new EventHandler(EventRunner.create());
        handler.removeTask(mHideRunnable);
        mSnacks.clear();
    }

    /*
     * Q Management *
     */

    public boolean isEmpty() {
        return mSnacks.isEmpty();
    }

    public Snack peek() {
        return mSnacks.peek().snack;
    }

    public Snack pollSnack() {
        return mSnacks.poll().snack;
    }

    public void clearSnacks(boolean animate) {
        mSnacks.clear();
        handler = new EventHandler(EventRunner.create());
        handler.removeTask(mHideRunnable);
        if (animate) mHideRunnable.run();
    }

    /*
     * Showing Logic *
     */

    public boolean isShowing() {
        return !mSnacks.isEmpty();
    }

    public void hide() {
        handler = new EventHandler(EventRunner.create());
        handler.removeTask(mHideRunnable);
        mHideRunnable.run();
    }

    public void showSnack(Snack snack, Component snackView, SnackBar.OnVisibilityChangeListener listener) {
        showSnack(snack, snackView, listener, false);
    }

    public void showSnack(Snack snack, Component snackView, SnackBar.OnVisibilityChangeListener listener, boolean immediately) {
        if (snackView.getComponentParent() != null && snackView.getComponentParent() != this) {
            snackView.getComponentParent().removeComponent(snackView);
        }

        SnackHolder holder = new SnackHolder(snack, snackView, listener);
        mSnacks.offer(holder);
        if (mSnacks.size() == 1) showSnack(holder, immediately);
    }

    private void showSnack(final SnackHolder holder) {
        showSnack(holder, false);
    }

    private void showSnack(final SnackHolder holder, boolean showImmediately) {

        setVisibility(Component.VISIBLE);

        sendOnShow(holder);
        LayoutConfig layoutConfig = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        layoutConfig.alignment = TextAlignment.BOTTOM;
        addComponent(holder.snackView, layoutConfig);
        holder.messageView.setText(holder.snack.mMessage);
        if (holder.snack.mActionMessage != null) {
            holder.button.setVisibility(Component.VISIBLE);
            holder.button.setText(holder.snack.mActionMessage);
        } else {
            holder.button.setVisibility(Component.HIDE);
        }

        holder.button.setFont(holder.snack.mTypeface);
        holder.messageView.setFont(holder.snack.mTypeface);

        Color color1 = new Color(holder.snack.mBtnTextColor);
        holder.button.setTextColor(color1);
        RgbColor rgbColor = RgbColor.fromArgbInt(holder.snack.mBackgroundColor);
        ShapeElement element = new ShapeElement();
        element.setRgbColor(rgbColor);
        holder.snackView.setBackground(element);
        if (holder.snack.mHeight > 0)
            holder.snackView.getLayoutConfig().height = this.getPxFromDp(holder.snack.mHeight);

        if (showImmediately) {
            mSlideInAnimation.setDuration(0);
        } else {
            mSlideInAnimation.setDuration(ANIMATION_DURATION);
        }
        mSlideInAnimation.setTarget(holder.snackView);
        mSlideOutAnimation.setTarget(holder.snackView);
        mSlideInAnimation.start();

        if (holder.snack.mDuration > 0) {
            handler = new EventHandler(EventRunner.getMainEventRunner());
            handler.postTask(mHideRunnable, holder.snack.mDuration);
        }
    }

    private void sendOnHide(SnackHolder snackHolder) {
        if (snackHolder.visListener != null) {
            snackHolder.visListener.onHide(mSnacks.size());
        }
    }

    private void sendOnShow(SnackHolder snackHolder) {
        if (snackHolder.visListener != null) {
            snackHolder.visListener.onShow(mSnacks.size());
        }
    }

    /*
     * Runnable stuff
     */

    private final Runnable mHideRunnable = new Runnable() {
        @Override
        public void run() {
            if (Component.VISIBLE == getVisibility()) {
                mSlideOutAnimation.start();
            }
        }
    };

    public void restoreState(Intent state, Component v) {
        Sequenceable[] messages = state.getParcelableArrayParam(SAVED_MSGS);
        boolean showImmediately = true;

        for (Sequenceable message : messages) {
            showSnack((Snack) message, v, null, showImmediately);
            showImmediately = false;
        }
    }

    public Intent saveState() {
        Intent outState = new Intent();

        final int count = mSnacks.size();
        final Snack[] snacks = new Snack[count];
        int i = 0;
        for (SnackHolder holder : mSnacks) {
            snacks[i++] = holder.snack;
        }

        outState.setParam(SAVED_MSGS, snacks);
        return outState;
    }

    private static class SnackHolder {
        final Component snackView;
        final Text messageView;
        final Text button;

        final Snack snack;
        final SnackBar.OnVisibilityChangeListener visListener;

        private SnackHolder(Snack snack, Component snackView, SnackBar.OnVisibilityChangeListener listener) {
            this.snackView = snackView;
            button = (Text) snackView.findComponentById(ResourceTable.Id_snackButton);
            messageView = (Text) snackView.findComponentById(ResourceTable.Id_snackMessage);

            this.snack = snack;
            visListener = listener;
        }
    }

    /*
     * Helpers
     */
    private int getPxFromDp(int dp) {
        int pxConverter = 2;
        int px = pxConverter * dp;
        return px;
    }

}
